package cn.example.converter;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLCreateIndexStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTruncateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.util.JdbcConstants;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Auther: CongKe
 * @Date: 2025/5/15 16:17
 * @Description: BaseConverter
 */
@Slf4j(topic = "sql-adapter")
public abstract class BaseConverter {

    /**
     * createTable sql语句
     */
    public List<String> creatTableList = new ArrayList<>();

    /**
     * comment sql语句
     */
    public List<String> commentList = new ArrayList<>();

    /**
     * index sql语句
     */
    public List<String> indexList = new ArrayList<>();

    /**
     * alter sql语句
     */
    public List<String> alterList = new ArrayList<>();

    /**
     * insert sql语句
     */
    public List<String> insertList = new ArrayList<>();

    /**
     * update sql语句
     */
    public List<String> updateList = new ArrayList<>();

    /**
     * select sql语句
     */
    public List<String> selectList = new ArrayList<>();

    /**
     * sequence sql语句
     */
    public List<String> sequenceList = new ArrayList<>();

    /**
     * alterSequence sql语句
     */
    public List<String> alterSequenceList = new ArrayList<>();

    /**
     * sql别名及函数
     */
    public final Map<String, SQLExpr> selectAliasMap = new HashMap<>();

    /**
     * SQL语法树映射
     */
    private final Map<Class<?>, Consumer<Object>> conversionStrategies = new HashMap<>();

    /**
     * 初始化策略映射
     */
    public BaseConverter() {
        conversionStrategies.put(MySqlCreateTableStatement.class, stmt -> convertCreateTabletStatement((MySqlCreateTableStatement) stmt));
        conversionStrategies.put(MySqlInsertStatement.class, stmt -> convertInsertStatement((MySqlInsertStatement) stmt));
        conversionStrategies.put(SQLCreateIndexStatement.class, stmt -> convertCreateIndexStatement((SQLCreateIndexStatement) stmt));
        conversionStrategies.put(MySqlUpdateStatement.class, stmt -> convertUpdateStatement((MySqlUpdateStatement) stmt));
        conversionStrategies.put(MySqlDeleteStatement.class, stmt -> convertDeleteStatement((MySqlDeleteStatement) stmt));
        conversionStrategies.put(SQLAlterTableStatement.class, stmt -> convertAlterTableStatement((SQLAlterTableStatement) stmt));
        conversionStrategies.put(MySqlRenameTableStatement.class, stmt -> convertRenameTableStatement((MySqlRenameTableStatement) stmt));
        conversionStrategies.put(SQLDropTableStatement.class, stmt -> convertDropTableStatement((SQLDropTableStatement) stmt));
        conversionStrategies.put(SQLTruncateStatement.class, stmt -> convertTruncateStatement((SQLTruncateStatement) stmt));
        conversionStrategies.put(SQLSelectStatement.class, stmt -> convertQueryStatement((SQLSelectStatement) stmt));
    }


    /**
     * 转换器适配
     *
     * @param dbType 数据库类型
     * @return 是否适配
     */
    abstract boolean support(String dbType);


    /**
     * 翻译转换
     *
     * @return 结果集
     */
    public List<String> convert(String schemaName, String originalSql) {
        List<SQLStatement> stmtList = SQLUtils.parseStatements(originalSql, JdbcConstants.MYSQL);
        List<String> result = new ArrayList<>();
        stmtList.forEach(statement -> {
            // 语法树翻译转化
            processConvertStatement(statement);
            List<String> collect = Stream.of(creatTableList, alterSequenceList, sequenceList, commentList, indexList, alterList, insertList, updateList, selectList).
                    flatMap(Collection::stream).
                    filter(Objects::nonNull).
                    collect(Collectors.toList());
            if (collect.isEmpty()) {
                collect.add(statement.toString());
            }
            result.addAll(collect);
        });

        return result;
    }

    /**
     * 语法树翻译转化
     *
     * @param statement 抽象语法树
     */
    private void processConvertStatement(SQLStatement statement) {
        Consumer<Object> consumer = conversionStrategies.get(statement.getClass());
        if (Objects.isNull(consumer)) {
            log.error("Unsupported statement type: " + statement.getClass());
            return;
        }
        consumer.accept(statement);
    }


    /**
     * DDL-CREATE 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertCreateTabletStatement(MySqlCreateTableStatement statement);

    /**
     * DML-INSERT 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertInsertStatement(MySqlInsertStatement statement);

    /**
     * DDL-INDEX 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertCreateIndexStatement(SQLCreateIndexStatement statement);

    /**
     * DML-UPDATE 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertUpdateStatement(MySqlUpdateStatement statement);

    /**
     * DML-DELETE 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertDeleteStatement(MySqlDeleteStatement statement);

    /**
     * DLL-ALTER TABLE 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertAlterTableStatement(SQLAlterTableStatement statement);

    /**
     * DDL-RENAME 语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertRenameTableStatement(MySqlRenameTableStatement statement);

    /**
     * DDL-Drop语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertDropTableStatement(SQLDropTableStatement statement);

    /**
     * 截断操作语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertTruncateStatement(SQLTruncateStatement statement);

    /**
     * 查询语法树转换
     *
     * @param statement 语法树
     */
    abstract void convertQueryStatement(SQLSelectStatement statement);

}
